﻿using System;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using Finance.GUI.ViewModels;
using Finance.ViewModels;

namespace Finance.Views
{
	internal partial class DocumentControl : UserControl
	{
		private readonly int _productNameColumnNumber;
		private readonly int _productPriceColumnNumber;

		protected float ProductHintRowHeight = 10;

		private readonly Color _gridEditErrorCellBackColor = Color.LightCoral;
		private readonly Color _gridEditCellBackColor;

		public DocumentControl()
		{
			InitializeComponent();

			_gridEditCellBackColor = _txtEdit.BackColor;
			
			var binding = new BindingSource();
			_productsDataGrid.DataSource = binding;

			_productNameColumnNumber = _productGridTableStyle.GridColumnStyles.IndexOf(_productNameColumn);
			_productPriceColumnNumber = _productGridTableStyle.GridColumnStyles.IndexOf(_productPriceColumn);

			_productsHintList.Visible = false;

			var productsHintBinding = new BindingSource();
			productsHintBinding.ListChanged += OnProductsSearchResultListChanged;
			_productsHintList.DataSource = productsHintBinding;

			var vScrollBar = (VScrollBar)_productsDataGrid.GetType().GetField("m_sbVert",
				BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance).GetValue(_productsDataGrid);

			var hScrollBar = (HScrollBar)_productsDataGrid.GetType().GetField("m_sbHorz",
				BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance).GetValue(_productsDataGrid);
			vScrollBar.ValueChanged += OnDataGridScrollBarValueChanged;
			hScrollBar.ValueChanged += OnDataGridScrollBarValueChanged;

			var graphics = CreateGraphics();
			var size = graphics.MeasureString("0", _productsHintList.Font);
			ProductHintRowHeight = size.Height+1;
		}

		void OnDataGridScrollBarValueChanged(object sender, EventArgs e)
		{
			if (!_inEditMode)
				return;

			UpdateEditTextBoxLocation();

			UpdateProductHintListLocation();
		}

		private void UpdateEditTextBoxLocation()
		{
			_txtEdit.BackColor = _gridEditCellBackColor;
			var cellPos = _productsDataGrid.GetCellBounds(_editCell.RowNumber, _editCell.ColumnNumber);
			_txtEdit.Left = cellPos.Left - 1;
			_txtEdit.Top = cellPos.Top + Top - 1;
			_txtEdit.Width = cellPos.Width + 2;
			_txtEdit.Height = cellPos.Height + 2;
		}

		
		public string Description
		{
			set { textBoxDescription.Text = value; }
			get { return textBoxDescription.Text; }
		}

		DocumentViewModel _documentViewModel;

		public DocumentViewModel DocumentViewModel
		{
			get { return _documentViewModel; }
			set
			{
				_documentBaseControl.ViewModel = value;

				if(value == null)
					return;

				_documentViewModel = value;

				Description = value.Description;

				if (!_documentViewModel.HasProductList && tabControl1.TabPages.Contains(tabPage1))
                    tabControl1.TabPages.RemoveAt(tabControl1.TabPages.IndexOf(tabPage1));

				textBoxDescription.DataBindings.Add(
					new Binding("Text", _documentViewModel, "Description", true, DataSourceUpdateMode.OnValidation));

				//Bind view
				//Products
				var productsBinding = ((BindingSource)_productsDataGrid.DataSource);
				productsBinding.DataSource = _documentViewModel.Products;
				_productGridTableStyle.MappingName = productsBinding.GetListName(null);

				//Products hint
				((BindingSource)_productsHintList.DataSource).DataSource = _documentViewModel.ProductsSearchResult;
			}
		}

		void OnProductsSearchResultListChanged(object sender, System.ComponentModel.ListChangedEventArgs e)
		{
			UpdateProductHintListLocation();
		}

		private void OnStartEditCell()
		{
			if (_editCell.ColumnNumber == _productNameColumnNumber)
			{
				_documentViewModel.SearchProductString = _txtEdit.Text;
			}
			UpdateProductHintListLocation();
		}

		private void OnCellTextChanged(DataGridCell editCell)
		{
			if (editCell.ColumnNumber == _productNameColumnNumber)
			{
				_documentViewModel.SearchProductString = _txtEdit.Text;
			}
		}

		public bool Apply()
		{
			_txtEdit.Update();

			if (_documentViewModel == null)
				return true;

			if (!_documentBaseControl.Apply())
				return false;
            
			return true;
		}

		private void OnDataGridDoubleClick(object sender, EventArgs e)
		{
			//Add empty row;
			_documentViewModel.NewProduct();
			//Enter edit mode
			OnDataGridCurrentCellChanged(sender, e);
			_txtEdit.Focus();
		}

		private DataGridCell _editCell;
		private bool _inEditMode = false;
		private bool _inUpdateMode = false;

		private void OnDataGridCurrentCellChanged(object sender, EventArgs e)
		{
			if (_inUpdateMode) return;
			if (_inEditMode && !_productsDataGrid.CurrentCell.Equals(_editCell))
			{
				// Update edited cell
				_inUpdateMode = true;
				Visible = false;
				var currentCell = _productsDataGrid.CurrentCell;
				
				UpdateCell();

				_productsDataGrid.CurrentCell = currentCell;
				Visible = true;
				_inUpdateMode = false;
				_txtEdit.Visible = false;
				_inEditMode = false;
			}

			// Enter edit mode
			_editCell = _productsDataGrid.CurrentCell;
			_txtEdit.Text = 
				_productsDataGrid[_editCell.RowNumber, _editCell.ColumnNumber] == null ? string.Empty :
				_productsDataGrid[_editCell.RowNumber, _editCell.ColumnNumber].ToString();
			UpdateEditTextBoxLocation();
			_txtEdit.Visible = true;
			_inEditMode = true;
			var valid = OnCellTextValidate(_editCell);

			_txtEdit.BackColor = valid
				? _gridEditCellBackColor
				: _gridEditErrorCellBackColor;

			OnStartEditCell();
		}

		private void UpdateProductHintListLocation()
		{
			if (_editCell.ColumnNumber == _productNameColumnNumber &&
				_documentViewModel.ProductsSearchResult.Count > 0)
			{
				//Place products hint list.
				var allowedPlaceAtTop = _txtEdit.Top;
				var allowedPlaceAtBottom = _productsDataGrid.Height - _txtEdit.Bottom;

				if (allowedPlaceAtBottom > _productsHintList.Height ||
				    allowedPlaceAtBottom > allowedPlaceAtTop)
				{
					_productsHintList.Top = _txtEdit.Bottom;
					_productsHintList.Height = Math.Min((int)
						(ProductHintRowHeight * _documentViewModel.ProductsSearchResult.Count), allowedPlaceAtBottom);
				}
				else
				{
					_productsHintList.Height = Math.Min((int)
						(ProductHintRowHeight * _documentViewModel.ProductsSearchResult.Count), allowedPlaceAtTop);
					_productsHintList.Top = _txtEdit.Top - _productsHintList.Height;
				}

				_productsHintList.Visible = true;
			}
			else
			{
				_productsHintList.Visible = false;
			}
		}

		private void UpdateCell()
		{
			var valid = OnCellTextValidate(_editCell);
				
			_txtEdit.BackColor = valid
				? _gridEditCellBackColor
				: _gridEditErrorCellBackColor;

			if (!valid)
				return;

			var oldValue = _productsDataGrid[_editCell.RowNumber, _editCell.ColumnNumber];
			if (oldValue is decimal)
			{
				try
				{
					_productsDataGrid[_editCell.RowNumber, _editCell.ColumnNumber] =
						string.IsNullOrEmpty(_txtEdit.Text) 
						? 0 : 
						decimal.Parse(_txtEdit.Text.Replace(".", System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator));
				}
				catch
				{
					_txtEdit.BackColor = _gridEditErrorCellBackColor;
					return;
				}
			}
			else
			{
				_productsDataGrid[_editCell.RowNumber, _editCell.ColumnNumber] = _txtEdit.Text;
			}
			_txtEdit.BackColor = _gridEditCellBackColor;
		}

		private void OnDataGridMouseUp(object sender, MouseEventArgs e)
		{
			var hitTest = _productsDataGrid.HitTest(e.X, e.Y);
			if (hitTest.Type != DataGrid.HitTestType.ColumnHeader) 
				return;

			// Exit edit mode
			_txtEdit.Visible = false;
			_inEditMode = false;
		}

		private void OnMenuItemRemoveProductClick(object sender, EventArgs e)
		{
			var rowIndexToRemove = _productsDataGrid.CurrentRowIndex;
			_documentViewModel.RemoveProductAt(rowIndexToRemove);
		}

		private void OnProductsContextMenuPopup(object sender, EventArgs e)
		{
			// Exit edit mode
			_txtEdit.Visible = false;
			_inEditMode = false;
		}

		private void OnEditTextChanged(object sender, EventArgs e)
		{
			if (!_inEditMode) return;
			UpdateCell();
			OnCellTextChanged(_editCell);
		}

		bool OnCellTextValidate(DataGridCell editCell)
		{
			if (editCell.ColumnNumber == _productNameColumnNumber)
			{
				return _txtEdit.Text.Length <= DocumentProductViewModel.MaxProductNameLength;
			}
			

			try
			{
				if(!string.IsNullOrEmpty(_txtEdit.Text))
					decimal.Parse(_txtEdit.Text.Replace(".", 
						System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator));
			}
			catch
			{
				return false;
			}
			
			return true;
		}

        private void OnProductsHintListSelectedIndexChanged(object sender, EventArgs e)
		{
			if (_productsHintList.SelectedIndex < 1) return;
			
			var productSearchResult = (ProductSearchResult) _productsHintList.SelectedItem;
			_txtEdit.Text = productSearchResult.Name;

			if(productSearchResult.Price != 0)
				_productsDataGrid[_editCell.RowNumber, _productPriceColumnNumber] = productSearchResult.Price;
		}
	}
}
